/*    file: main.cpp
 *    desc:
 * 
 * created: 2016-04-06
 *  author: chuanjiang.zh@qq.com
 * company: 
 */

#include <stdio.h>
#include <iostream>

#include "BasicType.h"
#include "RtmpCaster.h"
#include "Ffmpeg.h"
#include "SharedPtr.h"
#include "TFileUtil.h"
#include <assert.h>
#include "H264PropParser.h"
#include "TByteBuffer.h"
#include "PacketDumper.h"
#include "RtmpWriter.h"


struct CasterGuard
{
public:
    CasterGuard()
    {
        rtmpcaster_init();
    }

    ~CasterGuard()
    {
        rtmpcaster_quit();
    }
};

void DemoCasterEventCallback(const CasterEvent* event, void* context)
{
	printf("--- rtmp event. type:%d, name:%s\n", event->type, event->name);
}

void copyFormatTo(const av::MediaFormat& mfmt, MFormat* fmt)
{
	fmt->codec = mfmt.m_codec;
	fmt->width = mfmt.m_width;
	fmt->height = mfmt.m_height;
	fmt->framerate = mfmt.m_framerate;
	fmt->profile = mfmt.m_profile;
	fmt->clockRate = mfmt.m_clockRate;

	fmt->audioCodec = mfmt.m_audioCodec;
	fmt->channels = mfmt.m_channels;
	fmt->sampleRate = mfmt.m_sampleRate;
	fmt->audioProfile = mfmt.m_audioProfile;
	fmt->audioRate = mfmt.m_audioRate;

	fmt->vProp = (uint8_t*)mfmt.m_videoProp.c_str();
	fmt->vPropSize = mfmt.m_videoProp.size();

}

int main(int argc, char** argv)
{
	av_register_all();
	avformat_network_init();
	
	if (argc <= 1)
    {
        return EINVAL;
    }

	std::string	url = "rtmp://192.168.3.93/live/demo";
	if (argc > 2)
	{
		url = argv[2];
	}

    char* filename = argv[1];

	FILE* file = fopen(filename, "rb");
	if (file == NULL)
	{
		return -1;
	}

    CasterGuard casterGuard;
	//av::RtmpWriter writer;

	av::MediaFormat fmt;
	fmt.m_width = 1280;
	fmt.m_height = 720;
	fmt.m_codec = MCODEC_H264;
	fmt.m_profile = 66;
	fmt.m_framerate = 25;
	fmt.m_clockRate = 1000;

	MFormat mfmt;
	memset(&mfmt, 0, sizeof(mfmt));

	caster_t handle = -1;
	copyFormatTo(fmt, &mfmt);
	int rc = rtmpcaster_open(&handle, url.c_str(), &mfmt);

	rtmpcaster_set_event_callback(handle, DemoCasterEventCallback, NULL);

	std::string sps;
	std::string pps;

	comn::ByteBuffer buffer;
	comn::ByteBuffer paramBuffer;

	int64_t ptsStart = AV_NOPTS_VALUE;
	int64_t tmStart = av_gettime_relative();

	int64_t videoDuration = 0;
	int64_t audioDuration = 0;

	int frame_index = 0;

	int count = 100;
	while (true)
	{
		//count--;
		if (count <= 0)
		{
			break;
		}

		PacketHeader header;
		memset(&header, 0, sizeof(header));

		size_t length = fread(&header, 1, sizeof(header), file);
		if (length != sizeof(header))
		{
			break;
		}

		buffer.ensure(header.size);

		length = fread(buffer.data(), 1, header.size, file);
		if (length != header.size)
		{
			break;
		}

		buffer.resize(length);

		if (ptsStart == AV_NOPTS_VALUE)
		{
			ptsStart = header.pts;
		}

		header.pts = header.pts - ptsStart;
		/*
		if (header.type == MTYPE_VIDEO)
		{
			bool isParamNalu = false;

			av::NaluPacket nalu;
			av::H264PropParser::parseNalu(buffer.data(), header.size, nalu);
			if (nalu.type == av::NaluPacket::NALU_SPS)
			{
				sps.assign((char*)nalu.data, nalu.length);
				paramBuffer.write(buffer.data(), header.size);
				isParamNalu = true;
			}
			else if (nalu.type == av::NaluPacket::NALU_PPS)
			{
				pps.assign((char*)nalu.data, nalu.length);
				paramBuffer.write(buffer.data(), header.size);
				isParamNalu = true;
			}
			else if (nalu.type == av::NaluPacket::NALU_SEI)
			{
				paramBuffer.write(buffer.data(), header.size);
				isParamNalu = true;
			}

			if (fmt.m_videoProp.empty())
			{
				if (!sps.empty() && !pps.empty())
				{
					std::string sprop;
					sprop.append((char*)av::H264PropParser::getStartCode(), av::H264PropParser::START_CODE_LENGTH);
					sprop.append(sps);
					sprop.append((char*)av::H264PropParser::getStartCode(), av::H264PropParser::START_CODE_LENGTH);
					sprop.append(pps);

					fmt.m_videoProp.set(sprop.c_str(), sprop.size());

					//writer.open(url, fmt);
				}
			}

			if (isParamNalu)
			{
				continue;
			}

			if (nalu.type == av::NaluPacket::NALU_IFRAME)
			{
				comn::ByteBuffer buf(buffer);

				buffer.clear();
				buffer.write(paramBuffer.data(), paramBuffer.size());
				buffer.write(buf.data(), buf.size());

				paramBuffer.clear();
			}
		}
		*/

		AVPacket pkt;
		av_init_packet(&pkt);

		pkt.data = buffer.data();
		pkt.size = buffer.size();
		pkt.pts = header.pts;
		pkt.dts = header.pts;
		pkt.duration = header.duration;
		pkt.flags = header.flags;

		AVRational src = av_make_q(1, 1000000);
		AVRational dest = av_make_q(1, 1000);
		av_packet_rescale_ts(&pkt, src, dest);

		if (header.type == MTYPE_VIDEO)
		{
			//printf("Send %8d video frames. size:%d, duration:%d, pts:%I64d, dts:%I64d\n",
			//	frame_index, pkt.size, (int)pkt.duration, pkt.pts, pkt.dts);

			frame_index++;

			AVRational time_base_q = { 1, AV_TIME_BASE };
			int64_t pts_time = av_rescale_q(pkt.dts, dest, time_base_q);
			int64_t now_time = av_gettime_relative() - tmStart;
			if (pts_time > now_time)
			{
				av_usleep(pts_time - now_time);
			}
		}
		else
		{

		}

		//writer.write(pkt);

		MPacket mpkt;
		memset(&mpkt, 0, sizeof(mpkt));
		mpkt.type = header.type;
		mpkt.data = pkt.data;
		mpkt.size = pkt.size;
		mpkt.pts = pkt.pts;
		mpkt.duration = pkt.duration;
		mpkt.flags = pkt.flags;

		rtmpcaster_write(handle, &mpkt);
	}

	fclose(file);
	//writer.close();

	rtmpcaster_close(handle);

	std::cout << "enter any key to exit.\n";

	std::cin.get();

	return 0;
}




